package com.tang.framework.component;

import com.tang.common.component.RedisCache;
import com.tang.common.constant.Constant;
import com.tang.common.properties.sys.CoolTeaProperties;
import com.tang.framework.core.model.LoginUser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.tang.common.constant.Constant.TOKEN_HEADER;

/**
 * @author tang jun liang
 * @Date 2023/2/10 16:28
 */
@Component
public class TokenService {

    @Resource
    private RedisCache redisCache;


    @Resource
    private CoolTeaProperties coolTeaProperties;

    @Resource
    private HttpServletRequest request;

    public LoginUser getLoginUser(HttpServletRequest request) {
        String webToken = request.getHeader(TOKEN_HEADER);
        if (StringUtils.isBlank(webToken)){
            return null;
        }
        if (webToken.startsWith("Basic")){
            return null;
        }
        String token = getUserToken(getUid(webToken));

        LoginUser loginUser = redisCache.get(token);
        if (Objects.nonNull(loginUser) && loginUser.getToken().equals(request.getHeader(TOKEN_HEADER))) {
            return loginUser;
        }
        return null;
    }


    public void refresh(LoginUser loginUser) {
        String userToken = getUserToken(loginUser.getUserId());
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expireTime = now.plusHours(coolTeaProperties.getLoginSessionRefreshTime());
        Duration duration = Duration.between(now, expireTime);
        loginUser.setExpireTime(expireTime);
        redisCache.set(userToken, loginUser, duration.getSeconds(), TimeUnit.SECONDS);
    }


    public LoginUser createToken(LoginUser loginUser) {
        LocalDateTime now = LocalDateTime.now();
        loginUser.setExpireTime(now.plusHours(coolTeaProperties.getLoginSessionTimeOut()));
        String webToken = createUserToken(loginUser);
        String userToken = getUserToken(loginUser.getUserId());
        Duration duration = Duration.between(now, loginUser.getExpireTime());
        loginUser.setToken(webToken);
        redisCache.set(userToken, loginUser, duration.getSeconds(), TimeUnit.SECONDS);
        return loginUser;
    }


    private String createUserToken(LoginUser loginUser) {
        Map<String, Object> claims = new LinkedHashMap<>();
        claims.put(Constant.TOKEN_USER_ID_KEY, loginUser.getUserId());
        claims.put(Constant.EXPIRE_TIME, loginUser.getExpireTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss" )));
        return Jwts.builder()
                .addClaims(claims)
                .signWith(SignatureAlgorithm.HS512, coolTeaProperties.getTokenSecret())
                .compact();
    }


    private String getUserToken(Long uid) {
        return String.format(Constant.TOKEN_PATTERN, uid);
    }

    private Long getUid(String token) {
        try {
            return ((Integer) Jwts.parser().setSigningKey(coolTeaProperties.getTokenSecret())
                    .parseClaimsJws(token)
                    .getBody().get(Constant.TOKEN_USER_ID_KEY)).longValue();
        } catch (Exception e) {
            return 0L;
        }
    }
}
